package com.wengu.algorithm.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.wengu.algorithm.alg.*;
import com.wengu.algorithm.dto.TaskAlg;
import com.wengu.algorithm.dto.UserAlg;
import com.wengu.algorithm.entity.*;
import com.wengu.algorithm.mapper.TaskArrivalSpatialDistributionMapper;
import com.wengu.algorithm.mapper.TaskAssignmentScenarioMapper;
import com.wengu.algorithm.mapper.UserArrivalSpatialDistributionMapper;
import com.wengu.algorithm.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * <p>
 * 任务分配场景主表 服务实现类
 * </p>
 *
 * @author wanghailei
 * @since 2025-02-09
 */
@Slf4j
@Service
public class TaskAssignmentScenarioServiceImpl extends ServiceImpl<TaskAssignmentScenarioMapper, TaskAssignmentScenario> implements TaskAssignmentScenarioService {

    @Resource
    private TaskAssignmentScenarioMapper scenarioMapper;

    @Resource
    private TaskArrivalSpatialDistributionService taskService;

    @Resource
    private TaskArrivalSpatialDistributionMapper taskMapper;

    @Resource
    private UserArrivalSpatialDistributionService userService;
    @Resource
    private UserArrivalSpatialDistributionMapper userMapper;
    @Resource
    private AssignmentOutcomeService assignmentOutcomeService;
    @Resource
    private AssignmentOutcomeTaskService assignmentOutcomeTaskService;
    @Resource
    private AssignmentOutcomeUserService assignmentOutcomeUserService;


    private static final Random rand = new Random();
    /**
     * 总补偿比值的平均值
     */
    private final double budgetRatioMean = 7;
    /**
     * 总补偿比值(废弃)
     */
    private final double compensationRatio = 1;
    /**
     * 空间的长度
     */
    private final int spaceLength =100;

    /**
     * 空间的宽度
     */
    private final int spaceWidth =100;
    double sigma = 9;
    double alpha = 0;
    /**
     * 任务执行补偿费用均值
     */
    private double taskExecutionCostMean = 50;
    /**
     * 任务执行补偿费用标准差
     */
    private double taskExecutionCostStddev = 50;
    /**
     * 成功概率平均值
     */
    private double successProbMean = 0.8;
    /**
     * 任务持续时间均值
     */
    private double durationMean = 100;
    /**
     * 任务到达时间松柏速率
     */
    private double taskArrivalInterval = 1;


    /**
     * 质量函数
     */
//    private final String qualityFunction = "恒定值：1/" + TaskAlg.MAX_USER_COUNT;
//    private final String qualityFunction = "log：最大值" + TaskAlg.MAX_USER_COUNT;
    private final String qualityFunction = "多投票机制";
//    private final String weightWay = "对执行成本计算次幂";
    private final String weightWay = null;

    /**
     * 核心生成方法
     * 不考虑感知能力的算法适用的数据
     *
     * @return
     */
    @Override
    public String generateAllDataV1() {
        TaskAssignmentScenario maxBatchNoScenario = this.getOne(Wrappers.<TaskAssignmentScenario>lambdaQuery().eq(TaskAssignmentScenario::getDeleteFlag, 0).orderByDesc(TaskAssignmentScenario::getVersionNo), false);
        Integer versionNo = 0;
        if (maxBatchNoScenario != null) {
            versionNo = maxBatchNoScenario.getVersionNo();
        }
        versionNo++;
        for (int dataset = 0; dataset < 3; dataset++) {
            // 1. 创建主场景记录
            TaskAssignmentScenario scenario = createScenario(versionNo);
            scenarioMapper.insert(scenario);

            // 2. 生成任务数据
            generateTasks(scenario);

            // 3. 生成用户数据
            generateUsers(scenario);

            log.info("生成数据成功");
        }
        return versionNo.toString();
    }

    /**
     * 执行QEA算法
     *
     * @param versionNo
     * @param alpha
     */
//    @Transactional(rollbackFor = Exception.class)
    @Override
    public void executeGreedyAlgorithmQEA(Integer versionNo, Double alpha) {
        long start = System.currentTimeMillis();
        List<TaskAssignmentScenario> list = scenarioMapper.selectListByBatchNo(versionNo);
        String algName = "QEA";
        // 进行多少轮次模拟仿真，生成数据时就已确定本次执行需要执行多少轮次
        for (TaskAssignmentScenario taskAssignmentScenario : list) {
            long startFor = System.currentTimeMillis();
            QEA alg = new QEA(alpha);
            // 存储任务的执行次数及质量
            Map<Long, TaskAlg> taskCacheMap = new HashMap<>();
            // 不能再提升质量的任务集合，质量增量已经为0（质量总量=1的），使用double类型计算时已经为负的，则存储到该SET中，不进行计算
            Set<Long> notIncreaseTaskIdSet = new HashSet<>();
            // 保存执行结果主表信息
            AssignmentOutcome assignmentOutcome = assignmentOutcomeService.saveOutComeInit(taskAssignmentScenario, algName, alg,qualityFunction,weightWay);

            List<UserAlg> userAlgList = userMapper.selectListByMainId(taskAssignmentScenario.getId());
            // 该轮次有多少个用户进行模拟
            int i = 0;
            for (UserAlg userAlg : userAlgList) {
                List<TaskAlg> candidateTaskAlgList = taskMapper.selectListByMainIdAndDuration(taskAssignmentScenario.getId(), userAlg.getArrivalTime());
                // 调用qea算法执行
                List<TaskAlg> executableTaskAlgList = alg.allocateTasks(userAlg, candidateTaskAlgList, assignmentOutcome, assignmentOutcomeUserService, taskCacheMap, algName, notIncreaseTaskIdSet);
//                List<TaskAlg> executableTaskAlgList = alg.allocateTasksAsync(userAlg, candidateTaskAlgList, assignmentOutcome, assignmentOutcomeUserService, taskCacheMap, algName, notIncreaseTaskIdSet);
                log.info("第{}个用户[{}]候选任务个数[{}]，可执行的任务个数[{}]", ++i, userAlg.getId(), candidateTaskAlgList.size(), executableTaskAlgList.size());
            }
            // 每执行完一个轮次，保存结果，平均任务质量、单个任务的平均完成次数（完成任务的总的次数/任务总数/用户总数）
            assignmentOutcome.setExecuteTime(System.currentTimeMillis() - startFor);
            assignmentOutcomeTaskService.saveBatchOutcomeTask(assignmentOutcome, taskCacheMap);
            assignmentOutcomeService.updateQuality(assignmentOutcome);
        }

        log.info("执行结束，执行时间{}毫秒", (System.currentTimeMillis() - start));
    }
    /**
     * 执行QEA算法
     *
     * @param versionNo
     */
//    @Transactional(rollbackFor = Exception.class)
    @Override
    public void executeGreedyAlgorithmGenetic(Integer versionNo) {
        long start = System.currentTimeMillis();
        List<TaskAssignmentScenario> list = scenarioMapper.selectListByBatchNo(versionNo);
        String algName = "Genetic";
        // 进行多少轮次模拟仿真，生成数据时就已确定本次执行需要执行多少轮次
        for (TaskAssignmentScenario taskAssignmentScenario : list) {
            long startFor = System.currentTimeMillis();
            QEA alg = new Genetic();
            // 存储任务的执行次数及质量
            Map<Long, TaskAlg> taskCacheMap = new HashMap<>();
            // 不能再提升质量的任务集合，质量增量已经为0（质量总量=1的），使用double类型计算时已经为负的，则存储到该SET中，不进行计算
            Set<Long> notIncreaseTaskIdSet = new HashSet<>();
            // 保存执行结果主表信息
            AssignmentOutcome assignmentOutcome = assignmentOutcomeService.saveOutComeInit(taskAssignmentScenario, algName, alg,qualityFunction,weightWay);

            List<UserAlg> userAlgList = userMapper.selectListByMainId(taskAssignmentScenario.getId());
            // 该轮次有多少个用户进行模拟
            int i = 0;
            for (UserAlg userAlg : userAlgList) {
                List<TaskAlg> candidateTaskAlgList = taskMapper.selectListByMainIdAndDuration(taskAssignmentScenario.getId(), userAlg.getArrivalTime());
                // 调用qea算法执行
                List<TaskAlg> executableTaskAlgList = alg.allocateTasks(userAlg, candidateTaskAlgList, assignmentOutcome, assignmentOutcomeUserService, taskCacheMap, algName, notIncreaseTaskIdSet);
//                List<TaskAlg> executableTaskAlgList = alg.allocateTasksAsync(userAlg, candidateTaskAlgList, assignmentOutcome, assignmentOutcomeUserService, taskCacheMap, algName, notIncreaseTaskIdSet);
                log.info("第{}个用户[{}]候选任务个数[{}]，可执行的任务个数[{}]", ++i, userAlg.getId(), candidateTaskAlgList.size(), executableTaskAlgList.size());
            }
            // 每执行完一个轮次，保存结果，平均任务质量、单个任务的平均完成次数（完成任务的总的次数/任务总数/用户总数）
            assignmentOutcome.setExecuteTime(System.currentTimeMillis() - startFor);
            assignmentOutcomeTaskService.saveBatchOutcomeTask(assignmentOutcome, taskCacheMap);
            assignmentOutcomeService.updateQuality(assignmentOutcome);
        }

        log.info("执行结束，执行时间{}毫秒", (System.currentTimeMillis() - start));
    }

    @Override
    public void executeGreedyAlgorithmBQEA(Integer versionNo, Double heuristicWeight, Double bestSelectionProbability) {
        this.executeGreedyAlgorithmBQEA(versionNo,1.0,30,30,0.1,1.0 ,heuristicWeight,0.9 ,bestSelectionProbability);
    }

    /**
     * 执行BQEA算法
     *
     * @param versionNo
     * @param heuristicWeight
     * @param bestSelectionProbability
     */
//    @Transactional(rollbackFor = Exception.class)
    @Override
    public void executeGreedyAlgorithmBQEA(Integer versionNo, Double alpha,Integer antCount, Integer roundCount, Double initialPheromone, Double PheromoneWeight,Double heuristicWeight, Double evaporationRate, Double bestSelectionProbability) {
        long start = System.currentTimeMillis();
        List<TaskAssignmentScenario> list = scenarioMapper.selectListByBatchNo(versionNo);
        String algName = "BQEA";
        // 进行多少轮次模拟仿真，生成数据时就已确定本次执行需要执行多少轮次
        for (TaskAssignmentScenario taskAssignmentScenario : list) {
            long startFor = System.currentTimeMillis();
            BQEA alg = new BQEA(alpha,antCount, roundCount, initialPheromone, PheromoneWeight, heuristicWeight, evaporationRate, bestSelectionProbability);
            // 存储任务的执行次数及质量
            Map<Long, TaskAlg> taskCacheMap = new HashMap<>();
            // 不能再提升质量的任务集合，质量增量已经为0（质量总量=1的），使用double类型计算时已经为负的，则存储到该SET中，不进行计算
            Set<Long> notIncreaseTaskIdSet = new HashSet<>();
            // 保存执行结果主表信息
            AssignmentOutcome assignmentOutcome = assignmentOutcomeService.saveOutComeInit(taskAssignmentScenario, algName, alg, qualityFunction, weightWay);

            List<UserAlg> userAlgList = userMapper.selectListByMainId(taskAssignmentScenario.getId());
            // 该轮次有多少个用户进行模拟
            int i = 0;
            for (UserAlg userAlg : userAlgList) {
                List<TaskAlg> candidateTaskAlgList = taskMapper.selectListByMainIdAndDuration(taskAssignmentScenario.getId(), userAlg.getArrivalTime());
                // 调用qea算法执行
                List<TaskAlg> executableTaskAlgList = alg.allocateTasks(userAlg, candidateTaskAlgList, assignmentOutcome, assignmentOutcomeUserService, taskCacheMap, algName, notIncreaseTaskIdSet);
//                List<TaskAlg> executableTaskAlgList = alg.allocateTasksAsync(userAlg, candidateTaskAlgList, assignmentOutcome, assignmentOutcomeUserService, taskCacheMap, algName, notIncreaseTaskIdSet);
                log.info("第{}个用户[{}]候选任务个数[{}]，可执行的任务个数[{}]", ++i, userAlg.getId(), candidateTaskAlgList.size(), executableTaskAlgList.size());
            }
            // 每执行完一个轮次，保存结果，平均任务质量、单个任务的平均完成次数（完成任务的总的次数/任务总数/用户总数）
            assignmentOutcome.setExecuteTime(System.currentTimeMillis() - startFor);
            assignmentOutcomeTaskService.saveBatchOutcomeTask(assignmentOutcome, taskCacheMap);
            assignmentOutcomeService.updateQuality(assignmentOutcome);
        }

        log.info("执行结束，执行时间{}毫秒", (System.currentTimeMillis() - start));
    }


    /**
     * 执行ETDA算法
     *
     * @param versionNo
     * @param alpha
     * @param gamma
     */
//    @Transactional(rollbackFor = Exception.class)
    @Override
    public void executeGreedyAlgorithmETDA(Integer versionNo, Double alpha, Double gamma) {
        long start = System.currentTimeMillis();
        List<TaskAssignmentScenario> list = scenarioMapper.selectListByBatchNo(versionNo);
        String algName = "ETDA";

        // 验证alpha值，从0.1到1.0，总共执行10轮次，验证哪个值的效果更好
        for (int j = 0; j < 1; j++) {
//            sigma = sigma + 2;

            // 进行多少轮次模拟仿真，生成数据时就已确定本次执行需要执行多少轮次
            for (TaskAssignmentScenario taskAssignmentScenario : list) {
                long startFor = System.currentTimeMillis();
                ETDA alg = new ETDA(sigma, alpha, gamma);
                // 存储任务的执行次数及质量
                Map<Long, TaskAlg> taskCacheMap = new HashMap<>();
                // 不能再提升质量的任务集合，质量增量已经为0（质量总量=1的），使用double类型计算时已经为负的，则存储到该SET中，不进行计算
                Set<Long> notIncreaseTaskIdSet = new HashSet<>();
                // 保存执行结果主表信息
                AssignmentOutcome assignmentOutcome = assignmentOutcomeService.saveOutComeInit(taskAssignmentScenario, algName, alg, qualityFunction, weightWay);

                List<UserAlg> userAlgList = userMapper.selectListByMainId(taskAssignmentScenario.getId());
                // 该轮次有多少个用户进行模拟
                int i = 0;
                for (UserAlg userAlg : userAlgList) {
                    List<TaskAlg> candidateTaskAlgList = taskMapper.selectListByMainIdAndDuration(taskAssignmentScenario.getId(), userAlg.getArrivalTime());
                    // 调用qea算法执行
                List<TaskAlg> executableTaskAlgList = alg.allocateTasks(userAlg, candidateTaskAlgList, assignmentOutcome, assignmentOutcomeUserService, taskCacheMap, algName, notIncreaseTaskIdSet);
//                    List<TaskAlg> executableTaskAlgList = alg.allocateTasksAsync(userAlg, candidateTaskAlgList, assignmentOutcome, assignmentOutcomeUserService, taskCacheMap, algName, notIncreaseTaskIdSet);
                    log.info("第{}个用户[{}]候选任务个数[{}]，可执行的任务个数[{}]", ++i, userAlg.getId(), candidateTaskAlgList.size(), executableTaskAlgList.size());
                }
                // 每执行完一个轮次，保存结果，平均任务质量、单个任务的平均完成次数（完成任务的总的次数/任务总数/用户总数）
                assignmentOutcome.setExecuteTime(System.currentTimeMillis() - startFor);
                assignmentOutcomeTaskService.saveBatchOutcomeTask(assignmentOutcome, taskCacheMap);
                assignmentOutcomeService.updateQuality(assignmentOutcome);
            }
        }
        log.info("执行结束，执行时间{}毫秒", (System.currentTimeMillis() - start));
    }


    /**
     * 执行EDBA算法
     *
     * @param versionNo
     * @param alpha
     * @param gamma
     */
//    @Transactional(rollbackFor = Exception.class)
    @Override
    public void executeGreedyAlgorithmEDBA(Integer versionNo, Double alpha, Double gamma,Double mu) {
        long start = System.currentTimeMillis();
        List<TaskAssignmentScenario> list = scenarioMapper.selectListByBatchNo(versionNo);
        String algName = "EDBA";

        // 验证alpha值，从0.1到1.0，总共执行10轮次，验证哪个值的效果更好
        for (int j = 0; j < 1; j++) {
//            sigma = sigma + 2;

            // 进行多少轮次模拟仿真，生成数据时就已确定本次执行需要执行多少轮次
            for (TaskAssignmentScenario taskAssignmentScenario : list) {
                long startFor = System.currentTimeMillis();
                EDBA alg = new EDBA(alpha, gamma,mu);
                // 存储任务的执行次数及质量
                Map<Long, TaskAlg> taskCacheMap = new HashMap<>();
                // 不能再提升质量的任务集合，质量增量已经为0（质量总量=1的），使用double类型计算时已经为负的，则存储到该SET中，不进行计算
                Set<Long> notIncreaseTaskIdSet = new HashSet<>();
                // 保存执行结果主表信息
                AssignmentOutcome assignmentOutcome = assignmentOutcomeService.saveOutComeInit(taskAssignmentScenario, algName, alg, qualityFunction, weightWay);

                List<UserAlg> userAlgList = userMapper.selectListByMainId(taskAssignmentScenario.getId());
                // 该轮次有多少个用户进行模拟
                int i = 0;
                for (UserAlg userAlg : userAlgList) {
                    List<TaskAlg> candidateTaskAlgList = taskMapper.selectListByMainIdAndDuration(taskAssignmentScenario.getId(), userAlg.getArrivalTime());
                    // 调用qea算法执行
                List<TaskAlg> executableTaskAlgList = alg.allocateTasks(userAlg, candidateTaskAlgList, assignmentOutcome, assignmentOutcomeUserService, taskCacheMap, algName, notIncreaseTaskIdSet);
//                    List<TaskAlg> executableTaskAlgList = alg.allocateTasksAsync(userAlg, candidateTaskAlgList, assignmentOutcome, assignmentOutcomeUserService, taskCacheMap, algName, notIncreaseTaskIdSet);
                    log.info("第{}个用户[{}]候选任务个数[{}]，可执行的任务个数[{}]", ++i, userAlg.getId(), candidateTaskAlgList.size(), executableTaskAlgList.size());
                }
                // 每执行完一个轮次，保存结果，平均任务质量、单个任务的平均完成次数（完成任务的总的次数/任务总数/用户总数）
                assignmentOutcome.setExecuteTime(System.currentTimeMillis() - startFor);
                assignmentOutcomeTaskService.saveBatchOutcomeTask(assignmentOutcome, taskCacheMap);
                assignmentOutcomeService.updateQuality(assignmentOutcome);
            }
        }
        log.info("执行结束，执行时间{}毫秒", (System.currentTimeMillis() - start));
    }

    @Override
    public void executeGreedyAlgorithmBETDA(Integer versionNo, Double alpha, Double gamma) {
        this.executeGreedyAlgorithmBETDA(versionNo, alpha, gamma, 30,10, 0.1, 1.0, 3.0, 0.9, 0.1);
    }

    public void executeGreedyAlgorithmBETDA(Integer versionNo, Double alpha, Double gamma,
                                            int antCount, int roundCount,
                                            double initialPheromone, double pheromoneWeight,
                                            double heuristicWeight, double evaporationRate,
                                            double bestSelectionProbability) {
        long start = System.currentTimeMillis();
        List<TaskAssignmentScenario> list = scenarioMapper.selectListByBatchNo(versionNo);
        String algName = "BETDA";
        // 进行多少轮次模拟仿真，生成数据时就已确定本次执行需要执行多少轮次
        for (TaskAssignmentScenario taskAssignmentScenario : list) {
            long startFor = System.currentTimeMillis();
            BETDA alg = new BETDA(sigma, alpha,gamma,antCount, roundCount, initialPheromone, pheromoneWeight, heuristicWeight, evaporationRate, bestSelectionProbability);
            ETDA etda = new ETDA(sigma, alpha, gamma);
            // 存储任务的执行次数及质量
            Map<Long, TaskAlg> taskCacheMap = new HashMap<>();
            // 存储结果
            // 不能再提升质量的任务集合，质量增量已经为0（质量总量=1的），使用double类型计算时已经为负的，则存储到该SET中，不进行计算
            Set<Long> notIncreaseTaskIdSet = new HashSet<>();
            // 保存执行结果主表信息
            AssignmentOutcome assignmentOutcome = assignmentOutcomeService.saveOutComeInit(taskAssignmentScenario, algName, alg, qualityFunction, weightWay);

            List<UserAlg> userAlgList = userMapper.selectListByMainId(taskAssignmentScenario.getId());
            // 该轮次有多少个用户进行模拟
            int i = 0;
            for (UserAlg userAlg : userAlgList) {
                List<TaskAlg> candidateTaskAlgList = taskMapper.selectListByMainIdAndDuration(taskAssignmentScenario.getId(), userAlg.getArrivalTime());
                // 调用B-ETDA算法执行
                List<TaskAlg> executableTaskAlgList = alg.allocateTasks(userAlg, candidateTaskAlgList, assignmentOutcome, assignmentOutcomeUserService, taskCacheMap, algName, notIncreaseTaskIdSet,etda);
                log.info("第{}个用户[{}]候选任务个数[{}]，可执行的任务个数[{}]", ++i, userAlg.getId(), candidateTaskAlgList.size(), executableTaskAlgList.size());
            }
            // 每执行完一个轮次，保存结果，平均任务质量、单个任务的平均完成次数（完成任务的总的次数/任务总数/用户总数）
            assignmentOutcome.setExecuteTime(System.currentTimeMillis() - startFor);
            assignmentOutcomeTaskService.saveBatchOutcomeTask(assignmentOutcome, taskCacheMap);
            assignmentOutcomeService.updateQuality(assignmentOutcome);
        }
//        }
        log.info("执行结束，执行时间{}毫秒", (System.currentTimeMillis() - start));
    }

    @Override
    public void executeGreedyAlgorithmQPA(Integer versionNo) {
        long start = System.currentTimeMillis();
        List<TaskAssignmentScenario> list = scenarioMapper.selectListByBatchNo(versionNo);
        String algName = "QPA";
        // 进行多少轮次模拟仿真，生成数据时就已确定本次执行需要执行多少轮次
        for (TaskAssignmentScenario taskAssignmentScenario : list) {
            long startFor = System.currentTimeMillis();
            QPA alg = new QPA();
            // 存储临时的任务的执行次数及质量
            Map<Long, TaskAlg> taskCacheMap = new HashMap<>();
            // 存储真实的任务的执行次数及质量
            Map<Long, TaskAlg> realTaskCacheMap = new HashMap<>();
            // 不能再提升质量的任务集合，质量增量已经为0（质量总量=1的），使用double类型计算时已经为负的，则存储到该SET中，不进行计算
            Set<Long> notIncreaseTaskIdSet = new HashSet<>();
            // 保存执行结果主表信息
            AssignmentOutcome assignmentOutcome = assignmentOutcomeService.saveOutComeInitForQPA(taskAssignmentScenario, algName, alg, qualityFunction);

            List<UserAlg> userAlgList = userMapper.selectListByMainId(taskAssignmentScenario.getId());
            // 该轮次有多少个用户进行模拟
            int i = 0;
            for (UserAlg userAlg : userAlgList) {
                List<TaskAlg> candidateTaskAlgList = taskMapper.selectListByMainIdAndDuration(taskAssignmentScenario.getId(), userAlg.getArrivalTime());
                // 调用qea算法执行
                List<TaskAlg> executableTaskAlgList = alg.allocateTasks(userAlg, candidateTaskAlgList, assignmentOutcome, assignmentOutcomeUserService, taskCacheMap,realTaskCacheMap, algName, notIncreaseTaskIdSet);
//                List<TaskAlg> executableTaskAlgList = alg.allocateTasksAsync(userAlg, candidateTaskAlgList, assignmentOutcome, assignmentOutcomeUserService, taskCacheMap, algName, notIncreaseTaskIdSet);
                log.info("第{}个用户[{}]候选任务个数[{}]，可执行的任务个数[{}]", ++i, userAlg.getId(), candidateTaskAlgList.size(), executableTaskAlgList.size());
            }
            // 每执行完一个轮次，保存结果，平均任务质量、单个任务的平均完成次数（完成任务的总的次数/任务总数/用户总数）
            assignmentOutcome.setExecuteTime(System.currentTimeMillis() - startFor);
            assignmentOutcomeTaskService.saveBatchOutcomeTask(assignmentOutcome, realTaskCacheMap);
            assignmentOutcomeService.updateQuality(assignmentOutcome);
        }

        log.info("执行结束，执行时间{}毫秒", (System.currentTimeMillis() - start));
    }

    @Override
    public void executeGreedyAlgorithmTDA(Integer versionNo) {
        long start = System.currentTimeMillis();
        List<TaskAssignmentScenario> list = scenarioMapper.selectListByBatchNo(versionNo);
        String algName = "TDA";

        // 验证alpha值，从0.1到1.0，总共执行10轮次，验证哪个值的效果更好
        for (int j = 0; j < 1; j++) {
//            sigma = sigma + 2;

            // 进行多少轮次模拟仿真，生成数据时就已确定本次执行需要执行多少轮次
            for (TaskAssignmentScenario taskAssignmentScenario : list) {
                long startFor = System.currentTimeMillis();
                TDA alg = new TDA(sigma, alpha);
                // 存储临时的任务的执行次数及质量
                Map<Long, TaskAlg> taskCacheMap = new HashMap<>();
                // 存储真实的任务的执行次数及质量
                Map<Long, TaskAlg> realTaskCacheMap = new HashMap<>();
                // 不能再提升质量的任务集合，质量增量已经为0（质量总量=1的），使用double类型计算时已经为负的，则存储到该SET中，不进行计算
                Set<Long> notIncreaseTaskIdSet = new HashSet<>();
                // 保存执行结果主表信息
                AssignmentOutcome assignmentOutcome = assignmentOutcomeService.saveOutComeInitForQPA(taskAssignmentScenario, algName, alg, qualityFunction);

                List<UserAlg> userAlgList = userMapper.selectListByMainId(taskAssignmentScenario.getId());
                // 该轮次有多少个用户进行模拟
                int i = 0;
                for (UserAlg userAlg : userAlgList) {
                    List<TaskAlg> candidateTaskAlgList = taskMapper.selectListByMainIdAndDuration(taskAssignmentScenario.getId(), userAlg.getArrivalTime());
                    // 调用qea算法执行
                    List<TaskAlg> executableTaskAlgList = alg.allocateTasks(userAlg, candidateTaskAlgList, assignmentOutcome, assignmentOutcomeUserService, taskCacheMap, realTaskCacheMap, algName, notIncreaseTaskIdSet);
//                    List<TaskAlg> executableTaskAlgList = alg.allocateTasksAsync(userAlg, candidateTaskAlgList, assignmentOutcome, assignmentOutcomeUserService, taskCacheMap, algName, notIncreaseTaskIdSet);
                    log.info("第{}个用户[{}]候选任务个数[{}]，可执行的任务个数[{}]", ++i, userAlg.getId(), candidateTaskAlgList.size(), executableTaskAlgList.size());
                }
                // 每执行完一个轮次，保存结果，平均任务质量、单个任务的平均完成次数（完成任务的总的次数/任务总数/用户总数）
                assignmentOutcome.setExecuteTime(System.currentTimeMillis() - startFor);
                assignmentOutcomeTaskService.saveBatchOutcomeTask(assignmentOutcome, realTaskCacheMap);
                assignmentOutcomeService.updateQuality(assignmentOutcome);
            }
        }
        log.info("执行结束，执行时间{}毫秒", (System.currentTimeMillis() - start));
    }

    @Override
    public void executeGreedyAlgorithmPACO(Integer versionNo) {
        long start = System.currentTimeMillis();
        List<TaskAssignmentScenario> list = scenarioMapper.selectListByBatchNo(versionNo);
        String algName = "PACO";
        // 进行多少轮次模拟仿真，生成数据时就已确定本次执行需要执行多少轮次
        for (TaskAssignmentScenario taskAssignmentScenario : list) {
            long startFor = System.currentTimeMillis();
            QPA alg = new PACO();
            // 存储临时的任务的执行次数及质量
            Map<Long, TaskAlg> taskCacheMap = new HashMap<>();
            // 存储真实的任务的执行次数及质量
            Map<Long, TaskAlg> realTaskCacheMap = new HashMap<>();
            // 不能再提升质量的任务集合，质量增量已经为0（质量总量=1的），使用double类型计算时已经为负的，则存储到该SET中，不进行计算
            Set<Long> notIncreaseTaskIdSet = new HashSet<>();
            // 保存执行结果主表信息
            AssignmentOutcome assignmentOutcome = assignmentOutcomeService.saveOutComeInitForQPA(taskAssignmentScenario, algName, alg, qualityFunction);

            List<UserAlg> userAlgList = userMapper.selectListByMainId(taskAssignmentScenario.getId());
            // 该轮次有多少个用户进行模拟
            int i = 0;
            for (UserAlg userAlg : userAlgList) {
                List<TaskAlg> candidateTaskAlgList = taskMapper.selectListByMainIdAndDuration(taskAssignmentScenario.getId(), userAlg.getArrivalTime());
                // 调用qea算法执行
                List<TaskAlg> executableTaskAlgList = alg.allocateTasks(userAlg, candidateTaskAlgList, assignmentOutcome, assignmentOutcomeUserService, taskCacheMap,realTaskCacheMap, algName, notIncreaseTaskIdSet);
//                List<TaskAlg> executableTaskAlgList = alg.allocateTasksAsync(userAlg, candidateTaskAlgList, assignmentOutcome, assignmentOutcomeUserService, taskCacheMap, algName, notIncreaseTaskIdSet);
                log.info("第{}个用户[{}]候选任务个数[{}]，可执行的任务个数[{}]", ++i, userAlg.getId(), candidateTaskAlgList.size(), executableTaskAlgList.size());
            }
            // 每执行完一个轮次，保存结果，平均任务质量、单个任务的平均完成次数（完成任务的总的次数/任务总数/用户总数）
            assignmentOutcome.setExecuteTime(System.currentTimeMillis() - startFor);
            assignmentOutcomeTaskService.saveBatchOutcomeTask(assignmentOutcome, realTaskCacheMap);
            assignmentOutcomeService.updateQuality(assignmentOutcome);
        }

        log.info("执行结束，执行时间{}毫秒", (System.currentTimeMillis() - start));
    }

    @Override
    public void executeGreedyAlgorithmQEABatchAlpha(Integer versionNo) {
        List<Double> list = Arrays.asList(0.02, 0.04, 0.06, 0.08, 0.12, 0.14, 0.16, 0.18);
        for (Double v : list) {
            this.executeGreedyAlgorithmQEA(versionNo,v);
        }
//        for (int i = 0; i < 5; i++) {
//
//        }
    }

    @Override
    public void executeGreedyAlgorithmETDABatchBeta(Integer versionNo) {
        List<Double> list = Arrays.asList(0.3, 0.5, 0.7, 0.9);
        for (Double v : list) {
            this.executeGreedyAlgorithmETDA(versionNo,0.1,v);
        }
    }

    @Override
    public void executeGreedyAlgorithmEDBABatch(Integer versionNo) {
        for (int i = 0; i < 9; i++) {
            this.executeGreedyAlgorithmEDBA(versionNo,0.05, i * 1.0, 1.0);
        }
    }

    @Override
    public void executeGreedyAlgorithmBQEABatch(Integer versionNo) {
        List<Double> list = Arrays.asList(0.1);
        for (Double v : list) {
//        for (int i = 1; i < 5; i++) {
            this.executeGreedyAlgorithmBQEA(versionNo,v,30,30,0.1,1.0 ,5.0,0.9 ,0.1);
        }
    }

    @Override
    public void executeGreedyAlgorithmBatchBETDA(Integer versionNo) {
        List<Double> list = Arrays.asList(1.0,2.0,3.0,4.0,5.0);
        for (Double heuristicWeight : list) {
            this.executeGreedyAlgorithmBETDA(versionNo, 0.1, 0.1, 30,10, 0.1, 1.0, 4.0, 0.9, 0.1);
        }
    }


    private TaskAssignmentScenario createScenario(Integer versionNo) {
        TaskAssignmentScenario scenario = new TaskAssignmentScenario();
        scenario.setInitialTaskCount(0);
        scenario.setSpaceLength(spaceLength);
        scenario.setSpaceWidth(spaceWidth);
        // 任务到达的泊松速率1.0，该值越大，任务到达间隔时间越短
        scenario.setTaskArrivalInterval(taskArrivalInterval);
        // 用户到达的泊松速率1.0
        scenario.setUserArrivalInterval(1.0);
        scenario.setCreateDate(new Date());
        scenario.setUpdateDate(new Date());
        scenario.setDeleteFlag(0);
        scenario.setSkillFlag("0");
        scenario.setVersionNo(versionNo);
        scenario.setDuration(1000);
        scenario.setBudgetRatioMean(budgetRatioMean);
        scenario.setCompensationRatio(compensationRatio);
        scenario.setTaskExecutionCostMean(taskExecutionCostMean);
        scenario.setTaskExecutionCostStddev(taskExecutionCostStddev);
        scenario.setSuccessProbMean(successProbMean);
        return scenario;
    }

    private void generateTasks(TaskAssignmentScenario scenario) {
        List<TaskArrivalSpatialDistribution> tasks = new ArrayList<>();
        // 生成初始任务（10个，时间=0）
        for (int i = 0; i < scenario.getInitialTaskCount(); i++) {
            tasks.add(createTask(scenario.getId(), 0,
                    rand.nextDouble() * scenario.getSpaceLength() + rand.nextDouble() * 0.000001,
                    rand.nextDouble() * scenario.getSpaceWidth() + rand.nextDouble() * 0.000001,scenario));
        }

        // 生成后续任务（泊松过程）
        double currentTime = 0;
        // 泊松速率
        double lambda = scenario.getTaskArrivalInterval();
        while (currentTime <= scenario.getDuration() + 1) {
            tasks.add(createTask(scenario.getId(), currentTime,
                    rand.nextDouble() * scenario.getSpaceLength() + rand.nextDouble() * 0.000001,
                    rand.nextDouble() * scenario.getSpaceWidth() + rand.nextDouble() * 0.000001, scenario));
            double interval = -Math.log(1 - rand.nextDouble()) / lambda;
            currentTime += interval;
            if (currentTime > scenario.getDuration()) {
                break;
            }

        }

        // 批量插入
        taskService.saveBatch(tasks);
    }

    private TaskArrivalSpatialDistribution createTask(Long mainId, double arrivalTime, double x, double y, TaskAssignmentScenario scenario) {
        TaskArrivalSpatialDistribution task = new TaskArrivalSpatialDistribution();
        task.setMainId(mainId);
        task.setArrivalTime(arrivalTime);
        task.setTaskX(x);
        task.setTaskY(y);
        task.setCreateDate(new Date());
        task.setUpdateDate(new Date());
        task.setDeleteFlag(0);
        task.setDuration(Math.max(10,gaussian(durationMean, 30)));
        task.setEndTime(task.getArrivalTime() + task.getDuration());
        task.setExecutionCost(Math.max(1,gaussian(scenario.getTaskExecutionCostMean(), scenario.getTaskExecutionCostStddev())));
//        task.setExecutionCost(0d);
        task.setSuccessProb(clamp(gaussian(successProbMean, 0.15), 0.51, 0.99));
        return task;
    }

    private void generateUsers(TaskAssignmentScenario scenario) {
        List<UserArrivalSpatialDistribution> users = new ArrayList<>();

        // 生成用户（泊松过程）
        double currentTime = 0;
        double lambda = scenario.getUserArrivalInterval();
        while (currentTime <= scenario.getDuration()) {
            double interval = -Math.log(1 - rand.nextDouble()) / lambda;
            currentTime += interval;
            if (currentTime > scenario.getDuration()) {
                break;
            }
            // 用户到达位置
            double startX = rand.nextDouble() * scenario.getSpaceLength() + rand.nextDouble() * 0.000001;
            double startY = rand.nextDouble() * scenario.getSpaceWidth() + rand.nextDouble() * 0.000001;

            // 用户目的地坐标
            double destX = rand.nextDouble() * scenario.getSpaceLength() + rand.nextDouble() * 0.000001;
            double destY = rand.nextDouble() * scenario.getSpaceWidth() + rand.nextDouble() * 0.000001;

            users.add(createUser(scenario.getId(), currentTime, startX, startY, destX, destY));
        }

        userService.saveBatch(users);
    }

    private UserArrivalSpatialDistribution createUser(Long mainId, double arrivalTime, double startX, double startY, double destX, double destY) {
        UserArrivalSpatialDistribution user = new UserArrivalSpatialDistribution();
        user.setMainId(mainId);
        user.setArrivalTime(arrivalTime);
        user.setStartX(startX);
        user.setStartY(startY);
        user.setCreateDate(new Date());
        user.setUpdateDate(new Date());
        user.setDeleteFlag(0);

        // 以下字段需要实体类补充
        user.setDestX(destX);
        user.setDestY(destY);
        user.setBudgetRatio(Math.max(2, gaussian(budgetRatioMean, 0.6)));
        user.setCompensationRatio(compensationRatio);
        user.setBudget(QEA.calculateDistance(startX, startY, destX, destY) * user.getBudgetRatio());
        return user;
    }

    /**
     * 执行QEA算法
     *
     * @param versionNo
     */
//    @Transactional(rollbackFor = Exception.class)
    @Override
    public void executeGreedyAlgorithmQAOTO(Integer versionNo) {
        long start = System.currentTimeMillis();
        List<TaskAssignmentScenario> list = scenarioMapper.selectListByBatchNo(versionNo);
        String algName = "QAOTO";
        // 进行多少轮次模拟仿真，生成数据时就已确定本次执行需要执行多少轮次
        for (TaskAssignmentScenario taskAssignmentScenario : list) {
            long startFor = System.currentTimeMillis();
            QAOTO alg = new QAOTO();
            // 存储任务的执行次数及质量
            Map<Long, TaskAlg> taskCacheMap = new HashMap<>();
            Map<Long, TaskAlg> realTaskCacheMap = new HashMap<>();
            // 不能再提升质量的任务集合，质量增量已经为0（质量总量=1的），使用double类型计算时已经为负的，则存储到该SET中，不进行计算
            Set<Long> notIncreaseTaskIdSet = new HashSet<>();
            // 保存执行结果主表信息
            AssignmentOutcome assignmentOutcome = assignmentOutcomeService.saveOutComeInit(taskAssignmentScenario, algName, alg,qualityFunction,weightWay);

            List<UserAlg> userAlgList = userMapper.selectListByMainId(taskAssignmentScenario.getId());
            // 该轮次有多少个用户进行模拟
            int i = 0;
            for (UserAlg userAlg : userAlgList) {
                List<TaskAlg> candidateTaskAlgList = taskMapper.selectListByMainIdAndDuration(taskAssignmentScenario.getId(), userAlg.getArrivalTime());
                // 调用qea算法执行
                List<TaskAlg> executableTaskAlgList = alg.allocateTasksQAOTO(userAlg, candidateTaskAlgList, assignmentOutcome, assignmentOutcomeUserService, taskCacheMap, realTaskCacheMap,algName, notIncreaseTaskIdSet);
//                List<TaskAlg> executableTaskAlgList = alg.allocateTasksAsync(userAlg, candidateTaskAlgList, assignmentOutcome, assignmentOutcomeUserService, taskCacheMap, algName, notIncreaseTaskIdSet);
                log.info("第{}个用户[{}]候选任务个数[{}]，可执行的任务个数[{}]", ++i, userAlg.getId(), candidateTaskAlgList.size(), executableTaskAlgList.size());
            }
            // 每执行完一个轮次，保存结果，平均任务质量、单个任务的平均完成次数（完成任务的总的次数/任务总数/用户总数）
            assignmentOutcome.setExecuteTime(System.currentTimeMillis() - startFor);
            assignmentOutcomeTaskService.saveBatchOutcomeTask(assignmentOutcome, realTaskCacheMap);
            assignmentOutcomeService.updateQuality(assignmentOutcome);
        }

        log.info("执行结束，执行时间{}毫秒", (System.currentTimeMillis() - start));
    }

    @Override
    public void executeAlgorithmAll(Integer versionNo) {
        this.executeGreedyAlgorithmQEA(versionNo,1.0);
        this.executeGreedyAlgorithmQPA(versionNo);
        this.executeGreedyAlgorithmTDA(versionNo);
        this.executeGreedyAlgorithmETDA(versionNo,0.1,0.1);
        this.executeGreedyAlgorithmQAOTO(versionNo);
        this.executeGreedyAlgorithmPACO(versionNo);
        this.executeGreedyAlgorithmBETDA(versionNo,0.1,0.1);
    }

    // 高斯分布生成工具方法
    private static double gaussian(double mean, double stddev) {
        return mean + stddev * rand.nextGaussian();
    }

    // 数值范围限制
    private static double clamp(double value, double min, double max) {
        return Math.max(min, Math.min(max, value));
    }
}
